using System;
using System.Data;
using System.Text;
using System.Text.RegularExpressions;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Web.Script.Serialization;
using System.Web.Security;
using System.Xml;


/// <summary>
/// FacebookDataApi - utility class to implement a C# wrapper to the Facebook Data Store. Note, this requires the Facebook Toolkit from Claritycon.
/// </summary>
public static class FacebookDataApi
{
    #region user preferences api calls
    /// <summary>
    /// update one preference
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="pref_id">Numeric identifier of the preference to set.</param>
    /// <param name="value">string containing value to set.</param>
    /// <returns></returns>
    public static XmlDocument setUserPreference(Facebook.Components.FacebookService _fbService, int pref_id, string value)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(3);
        parameterList.Add("method", "facebook.data.setUserPreference");
        parameterList.Add("pref_id", pref_id.ToString());
        parameterList.Add("value", value);

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;
    }

    /// <summary>
    /// update multiple preferences in batch 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="values">Id-value pairs of preferences to set. Each id is an integer between 0 and 200 inclusively. Each value is a string with maximum length of 128 characters. Use "0" or "" to remove a preference. </param>
    /// <param name="replace">True to replace all existing preferences of this user; false to merge into existing preferences. </param>
    /// <returns></returns>
    public static XmlDocument setUserPreferences(Facebook.Components.FacebookService _fbService, IDictionary<string, string> values, bool replace)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(3);
        parameterList.Add("method", "facebook.data.setUserPreferences");
        parameterList.Add("values", formatAsJSONMap(values));
        parameterList.Add("replace", replace.ToString());

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;
    }

    /// <summary>
    /// Gets currently authenticated user's preference. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="pref_id">Numeric identifier of the preference to get.</param>
    /// <returns></returns>
    public static string getUserPreference(Facebook.Components.FacebookService _fbService, int pref_id)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(2);
        parameterList.Add("method", "facebook.data.getUserPreference");
        parameterList.Add("format", "JSON");
        parameterList.Add("pref_id", pref_id.ToString());

        return stripFirstAndLast(_fbService.ExecuteApiCallString(parameterList, true));
    }

    /// <summary>
    /// Gets currently authenticated user's all preferences.  
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="pref_id">Numeric identifier of the preference to get.</param>
    /// <returns></returns>
    public static Dictionary<string, string> getUserPreferences(Facebook.Components.FacebookService _fbService)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(1);
        parameterList.Add("method", "facebook.data.getUserPreferences");
        parameterList.Add("format", "JSON");

        string result = _fbService.ExecuteApiCallString(parameterList, true);
        result = result.Replace("{\"pref_id\":", "");
        result = result.Replace(",\"value\"", "");
        result = result.Replace("}", "");
        result = result.Replace("[", "{");
        result = result.Replace("]", "}");

        JavaScriptSerializer ser = new JavaScriptSerializer();
        return ser.Deserialize<Dictionary<string, string>>(result);
    }
    #endregion

    #region object type manipulation (DDL)
    /// <summary>
    /// Creates a new object type (like DDL). 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="name">Name of this new object type. </param>
    /// <returns></returns>
    public static XmlDocument createObjectType(Facebook.Components.FacebookService _fbService, string name)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(2);
        parameterList.Add("method", "facebook.data.createObjectType");
        parameterList.Add("name", name);

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    /// <summary>
    /// Remove a previously defined object type. This will also delete ALL objects of this type. This deletion is NOT reversible.
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="name">Name of the object type to delete. This will also delete all objects that were created with the type. </param>
    /// <returns></returns>
    public static XmlDocument dropObjectType(Facebook.Components.FacebookService _fbService, string obj_type)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(2);
        parameterList.Add("method", "facebook.data.dropObjectType");
        parameterList.Add("obj_type", obj_type);

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    /// <summary>
    /// Rename a previously defined object type. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_type">Previous name of the object type to rename.</param>
    /// <param name="new_name">New name to use.</param>
    /// <returns></returns>
    public static XmlDocument renameObjectType(Facebook.Components.FacebookService _fbService, string obj_type, string new_name)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(3);
        parameterList.Add("method", "facebook.data.renameObjectType");
        parameterList.Add("obj_type", obj_type);
        parameterList.Add("new_name", new_name);

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    /// <summary>
    /// Type of object property: 1 for integer, 2 for string (max. 255 characters), 3 for text blob (max. 64kb)
    /// </summary>
    public enum PropertyType
    {
        /// <summary>
        /// integer type
        /// </summary>
        integer_type = 1,
        /// <summary>
        /// string type (max. 255 characters)
        /// </summary>
        string_type = 2,
        /// <summary>
        /// text blob type (max. 64kb)
        /// </summary>
        text_blob = 3
    }

    /// <summary>
    /// Add a new object property to an object type. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_type">Object type to add a new property to.</param>
    /// <param name="prop_name">Name of the new property to add.</param>
    /// <param name="prop_type">Type of the new property: 1 for integer, 2 for string (max. 255 characters), 3 for text blob (max. 64kb)</param>
    /// <returns></returns>
    public static XmlDocument defineObjectProperty(Facebook.Components.FacebookService _fbService, string obj_type, string prop_name, PropertyType prop_type)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(4);
        parameterList.Add("method", "facebook.data.defineObjectProperty");
        parameterList.Add("obj_type", obj_type);
        parameterList.Add("prop_name", prop_name);
        parameterList.Add("prop_type", ((int)prop_type).ToString());

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    /// <summary>
    /// Remove a previously defined property of an object type. This will remove ALL values of this property of ALL objects of this type. This removal is NOT reversible. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_type">Object type from which a property is removed. </param>
    /// <param name="prop_name">Name of the property to remove. </param>
    /// <returns></returns>
    public static XmlDocument undefineObjectProperty(Facebook.Components.FacebookService _fbService, string obj_type, string prop_name)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(3);
        parameterList.Add("method", "facebook.data.undefineObjectProperty");
        parameterList.Add("obj_type", obj_type);
        parameterList.Add("prop_name", prop_name);

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    /// <summary>
    /// Rename a previously defined object property. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_type">Object type of the property to rename. </param>
    /// <param name="prop_name">Name of the property to change. </param>
    /// <param name="new_name"><New name to use. </param>
    /// <returns></returns>
    public static XmlDocument renameObjectProperty(Facebook.Components.FacebookService _fbService, string obj_type, string prop_name, string new_name)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(4);
        parameterList.Add("method", "facebook.data.renameObjectProperty");
        parameterList.Add("obj_type", obj_type);
        parameterList.Add("prop_name", prop_name);
        parameterList.Add("new_name", new_name);

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    /// <summary>
    /// Get a list of all previously defined object types. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <returns>list of object type definitions, each of which has: name: name of object type, object_class: (reserved) </returns>
    public static List<ObjectType> getObjectTypes(Facebook.Components.FacebookService _fbService)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(1);
        parameterList.Add("method", "facebook.data.getObjectTypes");
        parameterList.Add("format", "JSON");

        string result = _fbService.ExecuteApiCallString(parameterList, true);

        JavaScriptSerializer ser = new JavaScriptSerializer();
        return ser.Deserialize<List<ObjectType>>(result);
    }

    public class ObjectType
    {
        public string name;
        public PropertyType data_type;
        public int index_type;
    }

    /// <summary>
    /// Get detailed definitions of an object type, including all its properties and their types. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_type">Object type to get definition about. </param>
    /// <returns>list of object property definitions, each of which has: name: name of property; data_type: type of property (1 for integer, 2 for string - max. 255 characters, 3 for text blob - max. 64kb); index_type: (reserved) </returns>
    public static List<ObjectType> getObjectType(Facebook.Components.FacebookService _fbService, string obj_type)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(3);
        parameterList.Add("method", "facebook.data.getObjectType");
        parameterList.Add("format", "JSON");
        parameterList.Add("obj_type", obj_type);

        string result = _fbService.ExecuteApiCallString(parameterList, true);

        JavaScriptSerializer ser = new JavaScriptSerializer();
        return ser.Deserialize<List<ObjectType>>(result);

    }
    #endregion

    #region object manipulation

    /// <summary>
    /// Create a new object. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_type">Specifies which type of new object to create. </param>
    /// <param name="values">Optional - Name-value pairs of properties this new object has. </param>
    /// <returns>64-bit integer: Numeric identifier (fbid) of newly created object; -1 on error </returns>
    public static long createObject(Facebook.Components.FacebookService _fbService, string obj_type, IDictionary<string, string> properties)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(3);
        parameterList.Add("method", "facebook.data.createObject");
        parameterList.Add("format", "JSON");
        parameterList.Add("obj_type", obj_type);
        if (properties != null) parameterList.Add("properties", formatAsJSONMap(properties));

        string result = _fbService.ExecuteApiCallString(parameterList, true);

        long fbid = -1;
        try
        {
            fbid = Convert.ToInt64(result);
        }
        finally
        {
        }
        return fbid;
    }

    /// <summary>
    /// Create a new object. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_type">Specifies which type of new object to create. </param>
    /// <returns>64-bit integer: Numeric identifier (fbid) of newly created object; -1 on error </returns>
    public static long createObject(Facebook.Components.FacebookService _fbService, string obj_type)
    {
        return createObject(_fbService, obj_type, null);
    }

    /// <summary>
    /// Update an object's properties. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_id">Numeric identifier (fbid) of the object to modify. </param>
    /// <param name="values">Name-value pairs of new properties.</param>
    /// <param name="replace">True if replace all existing properties; false to merge into existing ones.</param>
    /// <returns></returns>
    public static XmlDocument updateObject(Facebook.Components.FacebookService _fbService, long obj_id, IDictionary<string, string> properties, bool replace)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(4);
        parameterList.Add("method", "facebook.data.updateObject");
        parameterList.Add("obj_id", obj_id.ToString());
        parameterList.Add("properties", formatAsJSONMap(properties));
        parameterList.Add("replace", replace.ToString());

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    /// <summary>
    /// Delete an object permanently. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_id">Numeric identifier (fbid) of the object to delete.</param>
    /// <returns></returns>
    public static XmlDocument deleteObject(Facebook.Components.FacebookService _fbService, long obj_id)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(2);
        parameterList.Add("method", "facebook.data.deleteObject");
        parameterList.Add("obj_id", obj_id.ToString());

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    /// <summary>
    /// Delete multiple objects permanently. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_ids">A list of 64-bit integers that are numeric identifiers (fbids) of objects to delete. </param>
    /// <returns></returns>
    public static XmlDocument deleteObjects(Facebook.Components.FacebookService _fbService, ICollection<long> obj_ids)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(2);
        parameterList.Add("method", "facebook.data.deleteObjects");
        parameterList.Add("obj_ids", formatAsJSONList<long>(obj_ids));

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    /// <summary>
    /// Get an object's properties. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_id">Numeric identifier (fbid) of the object to query.</param>
    /// <param name="prop_names">Optional - A list of property names (strings) to selectively query a subset of object properties. If not specified, all properties will be returned. </param>
    /// <returns>name-value pairs of specified properties of the object. </returns>
    public static Dictionary<string, string> getObject(Facebook.Components.FacebookService _fbService, long obj_id, ICollection<string> prop_names)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(2);
        parameterList.Add("method", "facebook.data.getObject");
        parameterList.Add("format", "JSON");
        parameterList.Add("obj_id", obj_id.ToString());
        if (prop_names != null) parameterList.Add("prop_names", formatAsJSONList<string>(prop_names));

        string results = _fbService.ExecuteApiCallString(parameterList, true);
        JavaScriptSerializer ser = new JavaScriptSerializer();
        return ser.Deserialize<Dictionary<string, string>>(results);
    }

    /// <summary>
    /// Get an object's properties. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_id">Numeric identifier (fbid) of the object to query.</param>
    public static Dictionary<string, string> getObject(Facebook.Components.FacebookService _fbService, long obj_id)
    {
        return getObject(_fbService, obj_id, null);
    }

    /// <summary>
    /// Get properties of multiple objects. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_ids">A list of 64-bit integers that are numeric identifiers (fbids) of objects to delete. </param>
    /// <param name="prop_names">Optional - A list of property names (strings) to selectively query a subset of object properties. If not specified, all properties will be returned. </param>
    /// <returns>A list of name-value pairs.</returns>
    public static List<Dictionary<string, string>> getObjects(Facebook.Components.FacebookService _fbService, ICollection<long> obj_ids, ICollection<string> prop_names)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(2);
        parameterList.Add("method", "facebook.data.getObjects");
        parameterList.Add("format", "JSON");
        parameterList.Add("obj_ids", formatAsJSONList<long>(obj_ids));
        if (prop_names != null) parameterList.Add("prop_names", formatAsJSONList<string>(prop_names));

        string results = _fbService.ExecuteApiCallString(parameterList, true);
        JavaScriptSerializer ser = new JavaScriptSerializer();
        return ser.Deserialize<List<Dictionary<string, string>>>(results);
    }

    /// <summary>
    /// Get properties of multiple objects. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_ids">A list of 64-bit integers that are numeric identifiers (fbids) of objects to delete. </param>
    /// <returns>A list of name-value pairs.</returns>
    public static List<Dictionary<string, string>> getObjects(Facebook.Components.FacebookService _fbService, ICollection<long> obj_ids)
    {
        return getObjects(_fbService, obj_ids, null);
    }

    /// <summary>
    /// Get a single property of an object. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_id">Object's numeric identifier (fbid). </param>
    /// <param name="prop_name">Property's name. </param>
    /// <returns>string: specified property's value. </returns>
    public static string getObjectProperty(Facebook.Components.FacebookService _fbService, long obj_id, string prop_name)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(4);
        parameterList.Add("method", "facebook.data.getObjectProperty");
        parameterList.Add("format", "JSON");
        parameterList.Add("obj_id", obj_id.ToString());
        parameterList.Add("prop_name", prop_name);

        return stripFirstAndLast(_fbService.ExecuteApiCallString(parameterList, true));
    }

    /// <summary>
    /// Set a single property of an object. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_id">Object's numeric identifier (fbid). </param>
    /// <param name="prop_name">Property's name. </param>
    /// <param name="prop_value">Property's value. </param>
    /// <returns></returns>
    public static XmlDocument setObjectProperty(Facebook.Components.FacebookService _fbService, long obj_id, string prop_name, string prop_value)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(3);
        parameterList.Add("method", "facebook.data.setObjectProperty");
        parameterList.Add("obj_id", obj_id.ToString());
        parameterList.Add("prop_name", prop_name);
        parameterList.Add("prop_value", prop_value);

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    /// <summary>
    /// Get a property value by a hash key. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_type">Object's type. This is required, so that different object types may use the same hash keys for different objects</param>
    /// <param name="key">Hash key (string object identifier) for locating the object. </param>
    /// <param name="prop_name">Name of the property to query. </param>
    /// <returns>string: property's value. Empty string will be returned (without any error), if object with the specified hash key was not found or created. </returns>
    public static string getHashValue(Facebook.Components.FacebookService _fbService, string obj_type, string key, string prop_name)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(5);
        parameterList.Add("method", "facebook.data.getHashValue");
        parameterList.Add("format", "JSON");
        parameterList.Add("obj_type", obj_type);
        parameterList.Add("key", key);
        parameterList.Add("prop_name", prop_name);

        return stripFirstAndLast(_fbService.ExecuteApiCallString(parameterList, true));
    }

    /// <summary>
    /// Set a property value by a hash key. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_type">Object's type. This is required so that different object types can use the same hash keys for different objects. </param>
    /// <param name="key">Hash key (string object identifier) for locating the object.</param>
    /// <param name="value">Property's value to set. </param>
    /// <param name="prop_name">Property's value to set. </param>
    /// <returns>64-bit integer: Numeric identifier (fbid) of the object. </returns>
    public static long setHashValue(Facebook.Components.FacebookService _fbService, string obj_type, string key, string value, string prop_name)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(6);
        parameterList.Add("method", "facebook.data.setHashValue");
        parameterList.Add("format", "JSON");
        parameterList.Add("obj_type", obj_type);
        parameterList.Add("key", key);
        parameterList.Add("value", value);
        parameterList.Add("prop_name", prop_name);

        return safeNumeric(_fbService.ExecuteApiCallString(parameterList, true));

    }

    /// <summary>
    /// Atomically increases a numeric property by a hash key. Note that this is different than "setHashValue(getHashValue() + increment)", which has two API functions calls that are not atomically done (subject to race conditions with values overwritten by interleaved API calls). 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_type">Object's type. This is required, so that different object types may use the same hash keys for different objects. </param>
    /// <param name="key">Hash key (string object identifier) for locating the object. </param>
    /// <param name="prop_name">Name of the property to set. </param>
    /// <param name="increment">Optional - Default is 1. Increments to add to current value, which is 0 if object was not found or created. Use negative number for decrements. </param>
    /// <returns>32-bit integer: property's value after incremented; -1 on error. </returns>
    public static int incHashValue(Facebook.Components.FacebookService _fbService, string obj_type, string key, string prop_name, int increment)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(6);
        parameterList.Add("method", "facebook.data.incHashValue");
        parameterList.Add("format", "JSON");
        parameterList.Add("obj_type", obj_type);
        parameterList.Add("key", key);
        parameterList.Add("prop_name", prop_name);
        if (increment != 1) parameterList.Add("increment", increment.ToString());

        string result = _fbService.ExecuteApiCallString(parameterList, true);

        int incremented = -1;
        try
        {
            incremented = Convert.ToInt32(result);
        }
        finally
        {
        }
        return incremented;
    }

    /// <summary>
    /// Atomically increases a numeric property by a hash key. Note that this is different than "setHashValue(getHashValue() + increment)", which has two API functions calls that are not atomically done (subject to race conditions with values overwritten by interleaved API calls). 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_type">Object's type. This is required, so that different object types may use the same hash keys for different objects. </param>
    /// <param name="key">Hash key (string object identifier) for locating the object. </param>
    /// <param name="prop_name">Name of the property to set. </param>
    /// <returns>32-bit integer: property's value after incremented; -1 on error. </returns>
    public static int incHashValue(Facebook.Components.FacebookService _fbService, string obj_type, string key, string prop_name)
    {
        return incHashValue(_fbService, obj_type, key, prop_name, 1);
    }

    /// <summary>
    /// Delete an object by a hash key. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_type">Object's type. This is required, so that different object types may use the same hash keys for different objects. </param>
    /// <param name="key">Hash key (string object identifier) to remove. </param>
    /// <returns></returns>
    public static XmlDocument removeHashKey(Facebook.Components.FacebookService _fbService, string obj_type, string key)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(3);
        parameterList.Add("method", "facebook.data.removeHashKey");
        parameterList.Add("obj_type", obj_type);
        parameterList.Add("key", key);

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    /// <summary>
    /// Delete multiple objects by a list of hash keys. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_type">Object's type. This is required, so that different object types may use the same hash keys for different objects. </param>
    /// <param name="keys">A list of hash keys (string object identifier) to remove. </param>
    /// <returns></returns>
    public static XmlDocument removeHashKeys(Facebook.Components.FacebookService _fbService, string obj_type, ICollection<string> keys)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(3);
        parameterList.Add("method", "facebook.data.removeHashKeys");
        parameterList.Add("obj_type", obj_type);
        parameterList.Add("keys", formatAsJSONList<string>(keys));

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }
    #endregion

    #region association data definition

    public enum AssociationType
    {
        /// <summary>
        /// 1: one-way association, where reverse lookup is not needed; 
        /// </summary>
        oneway = 1,
        /// <summary>
        /// 2: two-way symmetric association, where a backward association (B to A) is always created when a forward association (A to B) is created.
        /// </summary>
        twoway_symmetric = 2,
        /// <summary>
        /// 3: two-way asymmetric association, where a backward association (B to A) has different meaning than a forward association (A to B). 
        /// </summary>
        twoway_asymmetric = 3
    }

    public class AssociationInfo
    {
        /// <summary>
        /// Alise name of object identifier.
        /// </summary>
        public string alias;
        /// <summary>
        /// Original name of object identifier.
        /// </summary>
        public string object_type;
        /// <summary>
        /// Whether each unique object identifier can only appear once in all associations of this type.
        /// </summary>
        public bool unique;

        public AssociationInfo()
        {
        }

        public AssociationInfo(string alias, string object_type, bool unique)
        {
            this.alias = alias;
            this.object_type = object_type;
            this.unique = unique;
        }

        public AssociationInfo(string alias, string object_type) : this(alias, object_type, false) { }

        public AssociationInfo(string alias) : this(alias, null, false) { }
    }

    /// <summary>
    /// Defines a directional relationship between two object identifiers.
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="name">Name of forward association to create. </param>
    /// <param name="assoc_type">Type of this association; oneway, twoway_symmetric, twoway_asymmetric</param>
    /// <param name="assoc_info1">Describes object identifier 1 in an association. </param>
    /// <param name="assoc_info2">Describes object identifier 2 in an association. </param>
    /// <param name="inverse">Optional - name of backward association, if it is two-way asymmetric. </param>
    /// <returns></returns>
    public static XmlDocument defineAssociation(Facebook.Components.FacebookService _fbService, string name, AssociationType assoc_type, AssociationInfo assoc_info1, AssociationInfo assoc_info2, string inverse)
    {
        if (assoc_type == AssociationType.twoway_symmetric && inverse == null)
            throw (new Exception("Must specify inverse association for two-way assymetric."));

        Dictionary<string, string> parameterList = new Dictionary<string, string>(6);
        parameterList.Add("method", "facebook.data.defineAssociation");
        parameterList.Add("name", name);
        parameterList.Add("assoc_type", ((int)assoc_type).ToString());
        parameterList.Add("assoc_info1", formatAssociationInfoAsJSONMap(assoc_info1));
        parameterList.Add("assoc_info2", formatAssociationInfoAsJSONMap(assoc_info2));
        if (inverse != null) parameterList.Add("inverse", inverse);

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    /// <summary>
    /// Defines a directional relationship between two object identifiers.
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="name">Name of forward association to create. </param>
    /// <param name="assoc_type">Type of this association; oneway, twoway_symmetric, twoway_asymmetric</param>
    /// <param name="assoc_info1">Describes object identifier 1 in an association. </param>
    /// <param name="assoc_info2">Describes object identifier 2 in an association. </param>
    /// <param name="inverse">Optional - name of backward association, if it is two-way asymmetric. </param>
    public static XmlDocument defineAssociation(Facebook.Components.FacebookService _fbService, string name, AssociationType assoc_type, AssociationInfo assoc_info1, AssociationInfo assoc_info2)
    {
        if (assoc_type == AssociationType.twoway_symmetric)
            throw (new Exception("Must specify inverse association for two-way assymetric."));
        return defineAssociation(_fbService, name, assoc_type, assoc_info1, assoc_info2, null);
    }

    /// <summary>
    /// Remove a previously defined association. This will also delete this type of associations established between objects. This deletion is not reversible. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="name">Name of the association to remove. </param>
    /// <returns></returns>
    public static XmlDocument undefineAssociation(Facebook.Components.FacebookService _fbService, string name)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(2);
        parameterList.Add("method", "facebook.data.undefineAssociation");
        parameterList.Add("name", name);

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    /// <summary>
    /// Rename a previously defined association. Note that, any renaming here only affects one direction. To change names and aliases for another direction, rename with the name of that direction of association. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="name">Name of the association to change. </param>
    /// <param name="new_name">Optional - New name to use. </param>
    /// <param name="new_alias1">Optional - New alias for object identifier 1 to use. </param>
    /// <param name="new_alias2">Optional - New alias for object identifier 2 to use. </param>
    /// <returns></returns>
    public static XmlDocument renameAssociation(Facebook.Components.FacebookService _fbService, string name, string new_name, string new_alias1, string new_alias2)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(5);
        parameterList.Add("method", "facebook.data.renameAssociation");
        parameterList.Add("name", name);
        if (new_name != null) parameterList.Add("new_name", new_name);
        if (new_alias1 != null) parameterList.Add("new_alias1", new_alias1);
        if (new_alias2 != null) parameterList.Add("new_alias2", new_alias2);

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    /// <summary>
    /// Rename a previously defined association. Note that, any renaming here only affects one direction. To change names and aliases for another direction, rename with the name of that direction of association. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="name">Name of the association to change. </param>
    /// <param name="new_name">Optional - New name to use. </param>
    /// <param name="new_alias1">Optional - New alias for object identifier 1 to use. </param>
    /// <returns></returns>
    public static XmlDocument renameAssociation(Facebook.Components.FacebookService _fbService, string name, string new_name, string new_alias1)
    {
        return renameAssociation(_fbService, name, new_name, new_alias1, null);
    }

    /// <summary>
    /// Rename a previously defined association. Note that, any renaming here only affects one direction. To change names and aliases for another direction, rename with the name of that direction of association. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="name">Name of the association to change. </param>
    /// <param name="new_name">Optional - New name to use. </param>
    /// <returns></returns>
    public static XmlDocument renameAssociation(Facebook.Components.FacebookService _fbService, string name, string new_name)
    {
        return renameAssociation(_fbService, name, new_name, null, null);
    }

    /// <summary>
    /// Rename a previously defined association. Note that, any renaming here only affects one direction. To change names and aliases for another direction, rename with the name of that direction of association. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="name">Name of the association to change. </param>
    /// <returns></returns>
    public static XmlDocument renameAssociation(Facebook.Components.FacebookService _fbService, string name)
    {
        return renameAssociation(_fbService, name, null, null, null);
    }

    public class AssociationDefinition
    {
        public string name;
        public AssociationType assoc_type;
        public AssociationInfo assoc_info1;
        public AssociationInfo assoc_info2;
    }

    /// <summary>
    /// Get detailed definition of an association. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="name">Get detailed definition of an association. </param>
    /// <returns>An object association information data structure in JSON format. </returns>
    public static AssociationDefinition getAssociationDefinition(Facebook.Components.FacebookService _fbService, string name)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(3);
        parameterList.Add("method", "facebook.data.getAssociationDefinition");
        parameterList.Add("format", "JSON");
        parameterList.Add("name", name);

        string result = _fbService.ExecuteApiCallString(parameterList, true);

        JavaScriptSerializer ser = new JavaScriptSerializer();
        return ser.Deserialize<AssociationDefinition>(result);
    }

    /// <summary>
    /// Get detailed definitions of all previously defined associations. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <returns>An object association information data structure in JSON format. </returns>
    public static List<AssociationDefinition> getAssociationDefinitions(Facebook.Components.FacebookService _fbService)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(2);
        parameterList.Add("method", "facebook.data.getAssociationDefinitions");
        parameterList.Add("format", "JSON");

        string result = _fbService.ExecuteApiCallString(parameterList, true);

        JavaScriptSerializer ser = new JavaScriptSerializer();
        return ser.Deserialize<List<AssociationDefinition>>(result);
    }

    #endregion

    #region association data access

    public class Association : AssociationRef
    {
        /// <summary>
        /// Optional - An arbitrary data (max. 255 characters) to store with this association. 
        /// </summary>
        public string data;
        /// <summary>
        /// Optional - Default to association creation time. A timestamp to store with this association. This timestamp is represented as number of seconds since the Unix Epoch (January 1 1970 00:00:00 GMT). 
        /// </summary>
        public int assoc_time;

        public Association()
        {
        }

        public Association(string name, long obj_id1, long obj_id2, string data, int assoc_time)
        {
            this.name = name;
            this.id1 = obj_id1;
            this.id2 = obj_id2;
            this.data = data;
            this.assoc_time = assoc_time;
        }

        public Association(string name, long id1, long id2, string data) : this(name, id1, id2, data, 0) { }
        public Association(string name, long id1, long id2) : this(name, id1, id2, null, 0) { }

    }

    public class AssociationRef
    {
        /// <summary>
        /// Name of the association to set.
        /// </summary>
        public string name;
        /// <summary>
        /// Object identifier 1.
        /// </summary>
        public long id1;
        /// <summary>
        /// Object identifier 2. 
        /// </summary>
        public long id2;

        public AssociationRef()
        {
        }

        public AssociationRef(string name, long id1, long id2)
        {
            this.name = name;
            this.id1 = id1;
            this.id2 = id2;
        }
    }

    /// <summary>
    /// Creates an association between two object identifiers. Note that, the order of these two identifiers matters, unless this is a symmetric two-way association. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="name">Name of the association to set. </param>
    /// <param name="obj_id1">Object identifier 1. </param>
    /// <param name="obj_id2">Object identifier 2. </param>
    /// <param name="data">Optional - An arbitrary data (max. 255 characters) to store with this association. </param>
    /// <param name="assoc_time">Optional - Default to association creation time. A timestamp to store with this association. This timestamp is represented as number of seconds since the Unix Epoch (January 1 1970 00:00:00 GMT). </param>
    /// <returns></returns>
    public static XmlDocument setAssociation(Facebook.Components.FacebookService _fbService, string name, long obj_id1, long obj_id2, string data, int assoc_time)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(6);
        parameterList.Add("method", "facebook.data.setAssociation");
        parameterList.Add("name", name);
        parameterList.Add("obj_id1", obj_id1.ToString());
        parameterList.Add("obj_id2", obj_id2.ToString());
        if (data != null) parameterList.Add("data", data);
        if (assoc_time > 0) parameterList.Add("assoc_time", assoc_time.ToString());

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    /// <summary>
    /// Creates an association between two object identifiers. Note that, the order of these two identifiers matters, unless this is a symmetric two-way association. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="name">Name of the association to set. </param>
    /// <param name="obj_id1">Object identifier 1. </param>
    /// <param name="obj_id2">Object identifier 2. </param>
    /// <param name="data">Optional - An arbitrary data (max. 255 characters) to store with this association. </param>
    /// <returns></returns>
    public static XmlDocument setAssociation(Facebook.Components.FacebookService _fbService, string name, long obj_id1, long obj_id2, string data)
    {
        return setAssociation(_fbService, name, obj_id1, obj_id2, data, 0);
    }

    /// <summary>
    /// Creates an association between two object identifiers. Note that, the order of these two identifiers matters, unless this is a symmetric two-way association. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="name">Name of the association to set. </param>
    /// <param name="obj_id1">Object identifier 1. </param>
    /// <param name="obj_id2">Object identifier 2. </param>
    /// <returns></returns>
    public static XmlDocument setAssociation(Facebook.Components.FacebookService _fbService, string name, long obj_id1, long obj_id2)
    {
        return setAssociation(_fbService, name, obj_id1, obj_id2, null, 0);
    }

    /// <summary>
    /// Creates a list of associations. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="assocs">A list of associations to set. </param>
    /// <param name="name">Optional - default association name if association name is not specified in the list. </param>
    /// <returns></returns>
    public static XmlDocument setAssociations(Facebook.Components.FacebookService _fbService, ICollection<Association> assocs, string name)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(2);
        parameterList.Add("method", "facebook.data.setAssociations");
        parameterList.Add("assocs", formatAsJSONList<Association>(assocs));
        if (name != null) parameterList.Add("name", name);

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    /// <summary>
    /// Creates a list of associations. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="assocs">A list of associations to set. </param>
    /// <returns></returns>
    public static XmlDocument setAssociations(Facebook.Components.FacebookService _fbService, ICollection<Association> assocs)
    {
        return setAssociations(_fbService, assocs, null);
    }

    /// <summary>
    /// Removes an association between two object identifiers. Note that, the order of these two identifiers matters, unless this is a symmetric two-way association.
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="name">Name of the association. </param>
    /// <param name="obj_id1">Object identifier 1. </param>
    /// <param name="obj_id2">Object identifier 2. </param>
    /// <returns></returns>
    public static XmlDocument removeAssociation(Facebook.Components.FacebookService _fbService, string name, long obj_id1, long obj_id2)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(4);
        parameterList.Add("method", "facebook.data.removeAssociation");
        parameterList.Add("name", name);
        parameterList.Add("obj_id1", obj_id1.ToString());
        parameterList.Add("obj_id2", obj_id2.ToString());

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    /// <summary>
    /// Removes a list of associations. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="assocs">A list of associations to remove. </param>
    /// <param name="name">Optional - default association name if association name is not specified in the list. </param>
    /// <returns></returns>
    public static XmlDocument removeAssociations(Facebook.Components.FacebookService _fbService, ICollection<AssociationRef> assocs, string name)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(3);
        parameterList.Add("method", "facebook.data.removeAssociations");
        parameterList.Add("assocs", formatAsJSONList<AssociationRef>(assocs));
        if (name != null) parameterList.Add("name", name);

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    /// <summary>
    /// Removes a list of associations. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="assocs">A list of associations to remove. </param>
    /// <returns></returns>
    public static XmlDocument removeAssociations(Facebook.Components.FacebookService _fbService, ICollection<AssociationRef> assocs)
    {
        return removeAssociations(_fbService, assocs, null);
    }

    /// <summary>
    /// The name of this function may be misleading, but it actually removes associations between any other objects and a specified object. Those other associated objects will NOT be removed or deleted. Only the associations will be broken and deleted. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="name">Name of the association. </param>
    /// <param name="obj_id">Object identifier. </param>
    /// <returns></returns>
    public static XmlDocument removeAssociatedObjects(Facebook.Components.FacebookService _fbService, string name, long obj_id)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(3);
        parameterList.Add("method", "facebook.data.removeAssociatedObjects");
        parameterList.Add("name", name);
        parameterList.Add("obj_id", obj_id.ToString());

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    public class AssociatedObject
    {
        public long id2;
        public int time;
    }

    /// <summary>
    /// Returns a list of object ids that are associated with specified object. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="name">Name of the association. </param>
    /// <param name="obj_id">Object identifier. </param>
    /// <param name="no_data">True if only return object identifiers; false to return data and time as well. </param>
    /// <returns></returns>
    public static List<long> getAssociatedObjects(Facebook.Components.FacebookService _fbService, string name, long obj_id)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(5);
        parameterList.Add("method", "facebook.data.getAssociatedObjects");
        parameterList.Add("format", "JSON");
        parameterList.Add("name", name);
        parameterList.Add("obj_id", obj_id.ToString());
        parameterList.Add("no_data", "true");

        string results = _fbService.ExecuteApiCallString(parameterList, true);

        JavaScriptSerializer s = new JavaScriptSerializer();
        List<AssociatedObject> resultList = s.Deserialize<List<AssociatedObject>>(results);

        return resultList.ConvertAll<long>(new Converter<AssociatedObject, long>
        (
            delegate(AssociatedObject assoc_obj)
            {
                return assoc_obj.id2;
            }
        ));

    }

    /// <summary>
    /// Returns a list of object ids that are associated with specified object. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="name">Name of the association. </param>
    /// <param name="obj_id">Object identifier. </param>
    /// <param name="no_data">True if only return object identifiers; false to return data and time as well. </param>
    /// <returns></returns>
    public static List<AssociatedObject> getAssociatedObjects(Facebook.Components.FacebookService _fbService, string name, long obj_id, bool no_data)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(5);
        parameterList.Add("method", "facebook.data.getAssociatedObjects");
        parameterList.Add("format", "JSON");
        parameterList.Add("name", name);
        parameterList.Add("obj_id", obj_id.ToString());
        parameterList.Add("no_data", no_data.ToString());

        string results = _fbService.ExecuteApiCallString(parameterList, true);

        JavaScriptSerializer ser = new JavaScriptSerializer();
        return ser.Deserialize<List<AssociatedObject>>(results);
    }

    #region old code
    /*
            ////TODO: convert this to use JSON - the Xml could get really bloaty for large numbers of 
            //XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

            //List<long> objects = new List<long>();
            //XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
            //nsmgr.AddNamespace("fb", "http://api.facebook.com/1.0/");

            //foreach (XmlNode n in doc.SelectNodes("//fb:id2", nsmgr))
            //{
            //    try
            //    {
            //        long id = Convert.ToInt64(n.InnerText);
            //        objects.Add(id);
            //    }
            //    finally
            //    {
            //    }
            //}

            //return objects;
            */
    #endregion

    /// <summary>
    /// Returns count of object ids that are associated with specified object. This function takes constant time to return the count, regardless how many objects are associated.
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="name">Name of the association. </param>
    /// <param name="obj_id">Object identifier. </param>
    /// <returns>integer: count of associated objects of the specified object. </returns>
    public static long getAssociatedObjectCount(Facebook.Components.FacebookService _fbService, string name, long obj_id)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(4);
        parameterList.Add("method", "facebook.data.getAssociatedObjectCount");
        parameterList.Add("format", "JSON");
        parameterList.Add("name", name);
        parameterList.Add("obj_id", obj_id.ToString());

        return safeNumeric(_fbService.ExecuteApiCallString(parameterList, true));
    }

    /// <summary>
    /// Returns individual counts of object ids that are associated with a list of specified objects. This function takes constant time to return the counts, regardless how many objects are associated with each queried object. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="name">Name of the association. </param>
    /// <param name="obj_ids">A list of 64-bit numeric object identifiers. </param>
    /// <returns></returns>
    public static List<long> getAssociatedObjectCounts(Facebook.Components.FacebookService _fbService, string name, ICollection<long> obj_ids)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(4);
        parameterList.Add("method", "facebook.data.getAssociatedObjectCounts");
        parameterList.Add("format", "JSON");
        parameterList.Add("name", name);
        parameterList.Add("obj_ids", formatAsJSONList<long>(obj_ids));

        string result = _fbService.ExecuteApiCallString(parameterList, true);

        JavaScriptSerializer ser = new JavaScriptSerializer();
        return ser.Deserialize<List<long>>(result); ;
    }

    /// <summary>
    /// Get all associations between two object identifiers. 
    /// </summary>
    /// <param name="_fbService"></param>
    /// <param name="obj_id1">Object identifier 1. </param>
    /// <param name="obj_id2">Object identifier 2. </param>
    /// <param name="no_data">True if only return object identifiers; false to return data and time as well. </param>
    /// <returns></returns>
    public static XmlDocument getAssociations(Facebook.Components.FacebookService _fbService, long obj_id1, long obj_id2, bool no_data)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(6);
        parameterList.Add("method", "facebook.data.getAssociations");
        parameterList.Add("obj_id1", obj_id1.ToString());
        parameterList.Add("obj_id2", obj_id2.ToString());
        parameterList.Add("no_data", no_data.ToString());

        XmlDocument doc = _fbService.ExecuteApiCall(parameterList, true);

        return doc;

    }

    #endregion

    #region fql wrapper
    public static string directFqlCall(Facebook.Components.FacebookService _fbService, string query)
    {
        Dictionary<string, string> parameterList = new Dictionary<string, string>(4);
        parameterList.Add("method", "facebook.fql.query");
        parameterList.Add("format", "JSON");
        parameterList.Add("query", query);

        return _fbService.ExecuteApiCallString(parameterList, true);
    }

    #endregion

    #region private methods
    private static string formatAsJSONMap(IDictionary<string, string> values)
    {
        return jsonSerialiser(values);
        //StringBuilder sbValues = new StringBuilder();
        //foreach (KeyValuePair<string, string> item in values)
        //    sbValues.AppendFormat(",\"{0}\":\"{1}\"", item.Key, item.Value);
        //if (sbValues.Length > 0) sbValues.Remove(0, 1); // remove leading comma
        //sbValues.Insert(0, "{");
        //sbValues.Append("}");
        //return sbValues.ToString();
    }

    private static string formatAsJSONList<T>(ICollection<T> values)
    {
        return jsonSerialiser(values);
        //StringBuilder sbValues = new StringBuilder();
        //foreach (T item in values)
        //    sbValues.AppendFormat(",\"{0}\"", item);
        //if (sbValues.Length > 0) sbValues.Remove(0, 1); // remove leading comma
        //sbValues.Insert(0, "[");
        //sbValues.Append("]");
        //return sbValues.ToString();
    }

    private static string formatAssociationInfoAsJSONMap(AssociationInfo assoc_info)
    {
        return jsonSerialiser(assoc_info);
        //StringBuilder sbMap = new StringBuilder();
        //sbMap.AppendFormat("{\"alias\" : \"{0}\"", assoc_info.alias);
        //if(assoc_info.object_type != null) sbMap.AppendFormat(",\"object_type\" : \"{0}\"", assoc_info.object_type);
        //if (assoc_info.unique) sbMap.AppendFormat(",\"unique\" : \"{0}\"", assoc_info.unique);
        //sbMap.Append("}");
        //return sbMap.ToString();
    }

    public static string jsonSerialiser(object o)
    {
        JavaScriptSerializer ser = new JavaScriptSerializer();
        return ser.Serialize(o);
    }

    private static string stripSurroundingQuotes(string text)
    {
        Regex re = new Regex("\"(.*)\"");
        return re.Replace(text, "$1");
    }

    public static long safeNumeric(string convert)
    {
        long result = -1;
        try
        {
            convert = stripSurroundingQuotes(convert);
            result = Convert.ToInt64(convert);
        }
        catch 
        {
        }
        return result;
    }

    private static string stripFirstAndLast(string result)
    {
        if (result.Length > 2) result = result.Substring(1, result.Length - 2);
        return result;
    }

    #endregion
}
